#pragma once

#include <exception>

namespace platform {


#define THROW(Ex, Msg)			throw Ex(__FILE__, __LINE__, Msg)
#define THROW_PARAM(Ex, Msg, Param)	throw Ex(__FILE__, __LINE__, Msg, Param)

class Exception : public std::exception
{
	std::string _locationFile;
	unsigned long _locationLine;

	std::string _msg;
	std::string _param;

	mutable std::string _formatted;

public:
	inline Exception(const char *file, unsigned long line, const char *msg) throw ()
	: _locationFile(file), _locationLine(line), _msg(msg), _param()
	{}

	inline Exception(const char *file, unsigned long line, const char *msg, const char *param) throw ()
	: _locationFile(file), _locationLine(line), _msg(msg), _param(param)
	{}

	inline const std::string & getFile(void) const { return _locationFile; }
	inline unsigned long getLine(void) const { return _locationLine; }
	inline const std::string & getMessage(void) const { return _msg; }
	inline const std::string & getParameter(void) const { return _param; }

	inline const std::string & formatString(void) const {
		if (_formatted.empty()) {
			_formatted = "[";
			_formatted += _locationFile;
			_formatted += ','; _formatted += ' ';
			char bufLine[32];
			_snprintf_s(bufLine, 32, "%d", _locationLine);
			_formatted += bufLine;
			_formatted += ']'; _formatted += ' ';
			_formatted += _msg;
			if (!_param.empty()) {
				_formatted += ':'; _formatted += ' ';
				_formatted += _param;
			}
		}
		return _formatted;
	}

	virtual const char* what() const throw() {
		try {
			return formatString().c_str();
		} catch (...) {
			return "error";
		}
	}

};


} // end namespace
